﻿/*
 * KLF Headless Browser
 * Written by Kris Oye <kristianoye@gmail.com>
 * Copyright (C) 2011-2012.  All rights reserved.
 */
namespace KLF.Lib.Browser.DOM.HTML
{
    #region Using Statements

    using System.Linq;
    using System.Collections.Generic;

    #endregion

    /// <summary>
    /// An HTMLOptionsCollection is a list of nodes representing HTML option 
    /// element. An individual node may be accessed by either ordinal index 
    /// or the node's name or id attributes.
    /// 
    /// Note: Collections in the HTML DOM are assumed to be live meaning that
    /// they are automatically updated when the underlying document is changed.
    /// </summary>
    public class HTMLOptionsCollection
    {
        #region Properties

        internal List<Node> Nodes { get; set; }

        internal Document Owner { get; set; }

        #endregion

        #region Constructors

        internal HTMLOptionsCollection(Document owner, IEnumerable<Node> _recordsIn)
        {
            Nodes = new List<Node>(_recordsIn);
            Owner = owner;
        }

        #endregion

        #region HTML DOM Level 2 Compliance

        /// <summary>
        /// 
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public Node item(int index)
        {
            return (index > -1 && index < Nodes.Count ? Nodes[index] : null);
        }

        /// <summary>
        /// Returns the number of options in the list.
        /// </summary>
        public int length
        {
            get
            {
                return Nodes.Count;
            }
            set
            {
                throw new DOMException(DOMException.NOT_SUPPORTED_ERR);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public Node namedItem(string name)
        {
            if (Owner is HTMLDocument)
            {
                var result = Nodes.Where(e =>
                    (e as HTMLElement) != null &&
                    ((HTMLElement)e).id.ToLowerInvariant().Equals(name.ToLowerInvariant()));

                if (result.Count() == 0)
                {
                    result = Nodes.Where(e =>
                        (e as HTMLElement) != null &&
                        ((HTMLElement)e).getAttribute("name")
                            .ToLowerInvariant().Equals(name.ToLowerInvariant()));

                }
                return result.Count() > 0 ? result.First() : null;
            }
            else if (Owner is XHTMLDocument)
            {
                var result = Nodes.Where(e =>
                    (e as HTMLElement) != null &&
                    ((HTMLElement)e).id.Equals(name));

                if (result.Count() == 1)
                {
                    result = Nodes.Where(e =>
                        (e as HTMLElement) != null &&
                        ((HTMLElement)e).getAttribute("name").Equals(name));

                }
                return result.Count() > 0 ? result.First() : null;
            }
            else
            {
                throw new DOMException(DOMException.NOT_SUPPORTED_ERR);
            }
        }

        public HTMLOptionElement this[int index]
        {
            get
            {
                return (HTMLOptionElement)item(index);
            }
            set
            {
                if (index > Nodes.Count)
                    return;

                //  Appending a new item at options.length
                if (index == Nodes.Count && value != null)
                    Owner.appendChild(value);

                //  Replacing/deleting an existing option.
                if (index > -1 && index < Nodes.Count)
                {
                    HTMLElement e = Nodes[index] as HTMLOptionElement;

                    //  The new value is null--deelete
                    if (value == null)
                        e.Parent.removeChild(e);
                    //  The new value is present/different; Replace.
                    else
                    {
                        if (value != e)
                            e.Parent.replaceChild(value, e);
                    }
                }
            }
        }

        #endregion
    }
}
